package tech.waterism.adapter;

import org.springframework.stereotype.Component;
import tech.waterism.core.context.CalculationContext;
import tech.waterism.core.converter.ModelConverter;
import tech.waterism.core.model.*;
import tech.waterism.dto.*;
import tech.waterism.entity.FCurveHc;

import java.util.*;
import java.util.stream.Collectors;

/**
 * DTO-Model 适配器
 * 
 * <p>负责在原有的 DTO 对象和新的 core 模型对象之间进行转换
 * 
 * @author waterism
 * @since 1.0.0
 */
@Component
public class DtoModelAdapter {
    
    /**
     * 从 TopoDataDto 创建计算上下文
     * 
     * @param dto 调度数据DTO
     * @return 计算上下文
     */
    public CalculationContext createContext(TopoDataDto dto) {
        CalculationContext context = ModelConverter.createContext(
                dto.getFymdh(),
                dto.getSymdh(),
                dto.getMymdh(),
                dto.getDispatchType(),
                dto.getOutFlowType()
        );
        
        // 转换拓扑节点
        List<TopoNode> nodes = convertTopoObjects(dto.getTopoObject());
        context.setNodes(nodes);
        
        // 转换联调组
        if (dto.getDispatchObjects() != null) {
            List<JointDispatchGroup> groups = convertJointDispatchGroups(dto.getDispatchObjects());
            context.setJointGroups(groups);
        }
        
        return context;
    }
    
    /**
     * 转换拓扑对象列表
     * 
     * @param topoObjects 原始拓扑对象列表
     * @return 转换后的节点列表
     */
    public List<TopoNode> convertTopoObjects(List<TopoObjectDto> topoObjects) {
        if (topoObjects == null) {
            return new ArrayList<>();
        }
        
        return topoObjects.stream()
                .map(this::convertTopoObject)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个拓扑对象
     * 
     * @param dto 拓扑对象DTO
     * @return 拓扑节点
     */
    public TopoNode convertTopoObject(TopoObjectDto dto) {
        if (dto == null || dto.getFpIndex() == null) {
            return null;
        }
        
        FPIndexDto fpIndex = dto.getFpIndex();
        TopoNode node = new TopoNode();
        
        // 基本信息
        node.setStcd(fpIndex.getStcd());
        node.setStnm(fpIndex.getStnm());
        node.setPstcd(fpIndex.getPstcd());
        node.setOutcd(fpIndex.getOutcd());
        node.setDispatchType(dto.getDispatchType());
        node.setOutFlowType(fpIndex.getOutFlowType());
        node.setClen(fpIndex.getClen());
        node.setUnt(fpIndex.getUnt());
        
        // 时序数据
        node.setData(convertTimeSeriesData(fpIndex.getData()));
        
        // 输入分量
        node.setInputs(convertInputComponents(dto.getFpInputs()));
        
        // 基流
        node.setQBases(fpIndex.getQBases());
        
        // 水位库容曲线
        node.setCurveHs(convertCurveHc(fpIndex.getCurveHc()));
        
        // 调度规则ID
        node.setPrincipleId(fpIndex.getPrincipleId());
        
        // 枢纽信息
        if (fpIndex.getHub() != null) {
            node.setHub(convertHubInfo(fpIndex.getHub()));
        }
        
        // 洪水特性（FloodCharacterDto 类型不存在，暂时跳过）
        // if (fpIndex.getFloodCharacter() != null) {
        //     node.setFloodCharacter(convertFloodCharacter(fpIndex.getFloodCharacter()));
        // }
        
        return node;
    }
    
    /**
     * 转换时序数据列表
     */
    private List<TimeSeriesData> convertTimeSeriesData(List<ForecastDataDto> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        return dtoList.stream()
                .map(this::convertTimeSeriesDataItem)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个时序数据
     */
    private TimeSeriesData convertTimeSeriesDataItem(ForecastDataDto dto) {
        TimeSeriesData data = new TimeSeriesData();
        data.setDt(dto.getDt());
        data.setQ(dto.getQ());
        data.setRz(dto.getRz());
        data.setQReal(dto.getQReal());
        data.setQSim(dto.getQSim());
        data.setQPrep(dto.getQPrep());
        data.setQIn(dto.getQIn());
        data.setQOut(dto.getQOut());
        data.setV(dto.getV());
        data.setQDvr(dto.getQDvr());
        data.setQDsc(dto.getQDsc());
        data.setNUsedGates(dto.getNUsedGates());
        data.setFlowWay(dto.getFlowWay());
        return data;
    }
    
    /**
     * 转换输入分量列表
     */
    private List<InputComponent> convertInputComponents(List<FPInputDto> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        return dtoList.stream()
                .map(this::convertInputComponent)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个输入分量
     */
    private InputComponent convertInputComponent(FPInputDto dto) {
        InputComponent component = new InputComponent();
        component.setArtp(dto.getArtp());
        component.setArcd(dto.getArcd());
        component.setParcd(dto.getParcd());
        component.setPlcd(dto.getPlcd());
        component.setData(convertTimeSeriesData(dto.getData()));
        
        // 转换水文模型列表
        if (dto.getMdcdList() != null) {
            component.setMdcdList(convertModelInfoList(dto.getMdcdList()));
        }
        
        // 转换取水口列表
        if (dto.getIntakes() != null) {
            component.setIntakes(convertIntakeInfoList(dto.getIntakes()));
        }
        
        return component;
    }
    
    /**
     * 转换水文模型列表
     */
    private List<ModelInfo> convertModelInfoList(List<FMIndexDto> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        return dtoList.stream()
                .map(this::convertModelInfo)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个水文模型
     */
    private ModelInfo convertModelInfo(FMIndexDto dto) {
        ModelInfo info = new ModelInfo();
        info.setMdcd(dto.getMdcd());
        // FMIndexDto 可能没有 mdnm 字段，使用 mdcd 代替
        info.setMdnm(dto.getMdcd());
        // 参数可以根据需要扩展
        return info;
    }
    
    /**
     * 转换取水口列表
     */
    private List<IntakeInfo> convertIntakeInfoList(List<FPIntakeDto> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        return dtoList.stream()
                .map(this::convertIntakeInfo)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个取水口
     */
    private IntakeInfo convertIntakeInfo(FPIntakeDto dto) {
        IntakeInfo info = new IntakeInfo();
        // FPIntakeDto 的字段可能不完整，使用默认值
        // 实际应该从 dto 中获取取水口信息
        info.setIntakeCode("intake");
        info.setIntakeName("取水口");
        // 注意：IntakeDataDto 需要转换为 TimeSeriesData
        if (dto.getData() != null) {
            info.setData(convertIntakeData(dto.getData()));
        }
        return info;
    }
    
    /**
     * 转换取水量数据
     */
    private List<TimeSeriesData> convertIntakeData(List<IntakeDataDto> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        return dtoList.stream()
                .map(this::convertIntakeDataItem)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个取水量数据
     */
    private TimeSeriesData convertIntakeDataItem(IntakeDataDto dto) {
        TimeSeriesData data = new TimeSeriesData();
        data.setDt(dto.getDt());
        data.setQ(dto.getQ());
        return data;
    }
    
    /**
     * 转换水位库容曲线
     * <p>注意：FCurveHc 实际是水位耗水率曲线，这里只提取水位
     */
    private List<CurvePoint> convertCurveHc(List<FCurveHc> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        // FCurveHc 是水位耗水率曲线（z, c），这里将 c 作为 value
        // 实际的水位库容曲线应该从其他地方获取
        return dtoList.stream()
                .map(dto -> new CurvePoint(dto.getZ(), dto.getC()))
                .collect(Collectors.toList());
    }
    
    /**
     * 转换枢纽信息
     */
    private HubInfo convertHubInfo(DHubDefinationDto dto) {
        HubInfo info = new HubInfo();
        if (dto.getGate() != null) {
            info.setGate(convertGateInfoList(dto.getGate()));
        }
        return info;
    }
    
    /**
     * 转换闸门信息列表
     */
    private List<GateInfo> convertGateInfoList(List<DHubGateDto> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        return dtoList.stream()
                .map(this::convertGateInfo)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个闸门信息
     */
    private GateInfo convertGateInfo(DHubGateDto dto) {
        GateInfo info = new GateInfo();
        info.setGttp(dto.getGttp());
        info.setDtcd(dto.getDtcd());
        return info;
    }
    
    // convertFloodCharacter 方法已移除，因为 FloodCharacterDto 类型不存在
    
    /**
     * 转换联调组列表
     */
    private List<JointDispatchGroup> convertJointDispatchGroups(List<DispatchObjectDto> dtoList) {
        if (dtoList == null) {
            return new ArrayList<>();
        }
        
        return dtoList.stream()
                .filter(dto -> dto.getCalculate() == null || dto.getCalculate())
                .map(this::convertJointDispatchGroup)
                .collect(Collectors.toList());
    }
    
    /**
     * 转换单个联调组
     */
    private JointDispatchGroup convertJointDispatchGroup(DispatchObjectDto dto) {
        JointDispatchGroup group = new JointDispatchGroup();
        group.setJmsid(dto.getJmsid());
        group.setName("联调组-" + dto.getJmsid());
        group.setUpstreamNodes(dto.getUpDisNodes());
        // DispatchObjectDto 可能没有 endStcd 字段，使用最后一个节点作为终点
        if (dto.getDispatchObject() != null && !dto.getDispatchObject().isEmpty()) {
            TopoObjectDto lastNode = dto.getDispatchObject().get(dto.getDispatchObject().size() - 1);
            if (lastNode != null && lastNode.getFpIndex() != null) {
                group.setEndStcd(lastNode.getFpIndex().getStcd());
            }
        }
        group.setCalculate(dto.getCalculate());
        
        // 转换联调节点
        if (dto.getDispatchObject() != null) {
            group.setNodes(convertTopoObjects(dto.getDispatchObject()));
        }
        
        return group;
    }
    
    /**
     * 将计算结果同步回 DTO
     * 
     * @param node 拓扑节点
     * @param dto 拓扑对象DTO
     */
    public void syncResultToDto(TopoNode node, TopoObjectDto dto) {
        if (node == null || dto == null || dto.getFpIndex() == null) {
            return;
        }
        
        // 同步时序数据
        syncTimeSeriesData(node.getData(), dto.getFpIndex().getData());
    }
    
    /**
     * 同步时序数据
     */
    private void syncTimeSeriesData(List<TimeSeriesData> source, List<ForecastDataDto> target) {
        if (source == null || target == null) {
            return;
        }
        
        for (int i = 0; i < source.size() && i < target.size(); i++) {
            syncTimeSeriesDataItem(source.get(i), target.get(i));
        }
    }
    
    /**
     * 同步单个时序数据
     */
    private void syncTimeSeriesDataItem(TimeSeriesData source, ForecastDataDto target) {
        target.setQ(source.getQ());
        target.setRz(source.getRz());
        target.setQReal(source.getQReal());
        target.setQSim(source.getQSim());
        target.setQPrep(source.getQPrep());
        target.setQIn(source.getQIn());
        target.setQOut(source.getQOut());
        target.setV(source.getV());
        target.setQDvr(source.getQDvr());
        target.setQDsc(source.getQDsc());
        target.setNUsedGates(source.getNUsedGates());
        target.setFlowWay(source.getFlowWay());
    }
}

